#include "../hasten/cells.h"
#include "../vector_set.h"
#include "../ini/position.h"
#include "../run.h"

static void display_links( const mds_cells *cells )
{
	register unsigned i,j,k,l;
	const mds_cell *base = & cells->array[0][0][0];
	for( i=0; i < cells->num.x; ++i )
	{
		for( j=0; j < cells->num.y; ++j )
		{
			for( k=0; k < cells->num.z; ++k )
			{
				const mds_cell *cell = & cells->array[i][j][k];
				fprintf( stderr, "cell @%d: [%u %u %u] \n", (int)(cell-base),i,j,k);
				for( l=0; l < cell->num_neighbors; ++l )
				{
					const mds_cell *other = cell->neighbors[ l ];
					fprintf( stderr, " %d", (int)(other-base) );
				}
				fprintf( stderr, "\n");
			}
		}
	}
	
}


static void display_particles_in( const mds_cells *cells )
{
	register unsigned i,j,k;
	for( i=0; i < cells->num.x; ++i )
	{
		for( j=0; j < cells->num.y; ++j )
		{
			for( k=0; k < cells->num.z; ++k )
			{
				const mds_cell  *cell = & cells->array[i][j][k];
				const mds_pnode *node = cell->first;
				fprintf( stderr, "cell [%u %u %u] \n\t",i,j,k);
				while( node )
				{
					fprintf( stderr, " %u", (unsigned) node->id );
					node = node->next;
				}
				fprintf( stderr, "\n");
			}
		}
	}
	
}

int main()
{
	const Real   L   = 1.2;
	Real         r_c = 0.11;
	Real         Lc  = 0 ;
	const size_t Nc  = mds_cells_count1(&Lc, L, r_c); 
	mds_wtime    chrono;
	
	fprintf( stderr, "L=%g, cutoff=%g, Lc=%g, Nc=%u\n", L, r_c, Lc, (unsigned)Nc );
	fprintf( stderr, "sizeof(mds_cell)= %u\n", (unsigned)sizeof(mds_cell) );
	mds_run_initialize();
	mds_wtime_init( &chrono );
	
	{
		const mds_vector box   = { 2, 2, 2 };
		mds_cells        cells = MDS_CELLS_INIT;
		MDS_MEMORY();
		if( mds_cells_load( &cells, &box, 1) < 0 )
		{
			mds_perror( stderr, "mds_cells_load");
		}
		else
		{
			mds_vector_set     particles      = NULL;
			mds_pnode         *particle_nodes = NULL;
			const size_t       num_particles  = 100;
			mds_uvector cells_pbc = { 1, 1, 1};
			MDS_MEMORY();
			fprintf( stderr, "#cells= %u = [ %u %u %u ]\n", (unsigned) cells.count, (unsigned) cells.num.x, (unsigned) cells.num.y, (unsigned) cells.num.z );
			
			
			fprintf( stderr, "full pbc #links = %u\n", (unsigned)mds_cells_link( &cells, &cells_pbc) );
			display_links( &cells );
			
			
			
			cells_pbc.x = 0;
			fprintf( stderr, "yz only #links = %u\n", (unsigned)mds_cells_link( &cells, &cells_pbc) );
			display_links( &cells );
			
			cells_pbc.x = 1;
			(void)mds_cells_link( &cells, &cells_pbc);
			
			fprintf( stderr, "creating particles\n");
			particles      = mds_vector_set_create( num_particles );
			particle_nodes = mds_pnode_create( num_particles );
			if( !particles || !particle_nodes)
			{
				mds_perror( stderr, "particles/nodes" );
			}
			else
			{
				double ell = 0;
				register size_t iter    = 0;
				const    size_t itermax = 1000;
				fprintf( stderr, "Testing\n"); fflush( stderr );
				for( iter=0; iter < itermax; ++iter )
				{
					
					mds_position_initialize(particles, num_particles, mds_pbc_xyz, &box );
					mds_wtime_start( &chrono );
					mds_cells_dispatch( &cells, particles, particle_nodes, num_particles);
					ell += mds_wtime_query(&chrono);
				}
				display_particles_in( &cells );
				fprintf( stderr, "<dispatch>= %g ms\n", 1000.0 * ell / itermax ); 
			}
			
			mds_vector_set_delete( particles, num_particles);
			mds_pnode_delete( particle_nodes, num_particles);
			mds_cells_quit( &cells );
		}
		MDS_MEMORY();
	}
	
	{
		const mds_vector box = { 3.2, 3.5, 3.6 };
		mds_cells        cells = MDS_CELLS_INIT;
		MDS_MEMORY();
		if( mds_cells_load( &cells, &box, r_c) < 0 )
		{
			mds_perror( stderr, "mds_cells_load");
		}
		else
		{
			MDS_MEMORY();
			fprintf( stderr, "#cells= %u = [ %u %u %u ]\n", (unsigned) cells.count, (unsigned) cells.num.x, (unsigned) cells.num.y, (unsigned) cells.num.z );
			fprintf( stderr, "lengths    = [ %g %g %g ]\n", cells.length.x, cells.length.y, cells.length.z );
			mds_uvector cells_pbc = { 1, 1, 1};
			fprintf( stderr, "#links = %u\n", (unsigned)mds_cells_link( &cells, &cells_pbc) );
			cells_pbc.z = 0;
			fprintf( stderr, "#links = %u\n", (unsigned)mds_cells_link( &cells, &cells_pbc) );
		}
		
		mds_cells_quit( &cells );
		MDS_MEMORY();
	}
	
	
	return 0;
}
